package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.aliyun.GreenImageScan;
import com.heima.aliyun.GreenTextScan;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.service.WmNewsAutoScanService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.heima.model.common.constants.message.PublishArticleConstants.DELAY_DIRECT_EXCHANGE;
import static com.heima.model.common.constants.message.PublishArticleConstants.PUBLISH_ARTICLE_ROUTE_KEY;

@Slf4j
@Service
@SuppressWarnings("all")
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Value("${file.oss.web-site}")
    private String webSite;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private AdminFeign adminFeign;
    @Autowired
    private GreenTextScan textScan;
    @Autowired
    private GreenImageScan imageScan;
    @Autowired
    RabbitTemplate rabbitTemplate;

    /**
     * 自媒体文章审核
     *
     * @param id 自媒体文章id
     */
    @Override
    public void autoScanWmNews(Integer id) {
        // 1.参数校验
        if (id == null) {
            CustException.cust(AppHttpCodeEnum.PARAM_INVALID, "自媒体文章id不能为空");
        }
        // 1.1根据id查找文章
        WmNews wmNews = wmNewsMapper.selectById(id);
        if (wmNews == null) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "文章不存在");
        }

        // 1.2 查看文章的状态
        Short status = wmNews.getStatus();
        if (WmNews.Status.SUBMIT.getCode() != status) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_ALLOW, "当前文章不是处于可审核的状态");
        }
        // 2 抽取出文章的文本和图像
        Map<String, Object> contentAndImageResult = handleTextAndImages(wmNews);
        // 3.1  敏感词审核    失败   修改文章状态(2)
        Boolean isSensivice = handleSensitive((String) contentAndImageResult.get("content"), wmNews);
        if (isSensivice) return;
        // 3.2  阿里云的文本审核   失败  状态2  不确定 状态3
        Boolean isTextScan = handleTextScan((String) contentAndImageResult.get("content"), wmNews);
        if (!isTextScan) return;
        // 3.3  阿里云的图片审核   失败  状态2  不确定 状态3
        Object images = contentAndImageResult.get("images");
        if (images != null) {
            Boolean isImageScan = handleImageScan((List<String>) images, wmNews);
            if (!isImageScan) return;
        }
        updateWmNews(wmNews, WmNews.Status.SUCCESS.getCode(), "审核通过");

        // 4. 判断文章发布时间是否大于当前时间   状态 8
        long publishTime = wmNews.getPublishTime().getTime();
        long nowTime = System.currentTimeMillis();
        long remainTime = publishTime - nowTime;
        rabbitTemplate.convertAndSend(DELAY_DIRECT_EXCHANGE, PUBLISH_ARTICLE_ROUTE_KEY, wmNews.getId(), new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                message.getMessageProperties().setHeader("x-delay", remainTime <= 0 ? 0 : remainTime);
                return message;
            }
        });
        log.info("立即发布文章通知成功发送，文章id : {}", wmNews.getId());
    }


    /**
     * 阿里云的图像审核
     *
     * @param images
     * @param wmNews
     * @return
     */
    private Boolean handleImageScan(List<String> images, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = imageScan.imageUrlScan(images);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "图片有违规内容,审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "图片有不确定的违规内容,需要人工审核");
                    flag = false;
                    break;
            }

        } catch (Exception e) {
            e.printStackTrace();
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云内容服务异常，转为人工审核");
        }
        return flag;
    }

    /**
     * 阿里云的文本审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private Boolean handleTextScan(String content, WmNews wmNews) {
        boolean flag = true;
        try {
            Map map = textScan.greenTextScan(content);
            String suggestion = (String) map.get("suggestion");
            switch (suggestion) {
                case "block":
                    updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本有违规内容,审核失败");
                    flag = false;
                    break;
                case "review":
                    updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "文本有不确定的违规内容,需要人工审核");
                    flag = false;
                    break;
            }

        } catch (Exception e) {
            e.printStackTrace();
            updateWmNews(wmNews, WmNews.Status.ADMIN_AUTH.getCode(), "阿里云内容服务异常，转为人工审核");
        }
        return flag;
    }


    /**
     * 更改文章的状态
     *
     * @param wmNews
     * @param status
     * @param reason
     */
    private void updateWmNews(WmNews wmNews, short status, String reason) {
        wmNews.setStatus(status);
        wmNews.setReason(reason);
        wmNewsMapper.updateById(wmNews);
    }

    /**
     * 敏感词审核
     *
     * @param content
     * @param wmNews
     * @return
     */
    private Boolean handleSensitive(String content, WmNews wmNews) {
        boolean flag = false;
        // 获取数据库中所有敏感词
        ResponseResult<List<String>> sensitives = adminFeign.sensitives();
        //初始化敏感词数据
        SensitiveWordUtil.initMap(sensitives.getData());
        //对目标文本进行检验
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        if (map.size() > 0) {
            updateWmNews(wmNews, WmNews.Status.FAIL.getCode(), "文本中包含敏感词");
            flag = true;
        }
        return flag;
    }

    /**
     * 抽取出文本和图片
     *
     * @param wmNews
     * @return
     */
    private Map<String, Object> handleTextAndImages(WmNews wmNews) {
        // 1.抽取内容中的文本
        String contentJson = wmNews.getContent();
        if (StringUtils.isBlank(contentJson)) {
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST, "文章内容不存在");
        }
        // 1.2 将文本转换成一个list集合
        List<Map> contentMaps = JSON.parseArray(contentJson, Map.class);
        // 1.3 拿到所有集合中所有文本
        String content = contentMaps.stream()
                .filter(map -> "text".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.joining("_hmtt_"));
        // 2.抽取文章标题中的文本
        String title = wmNews.getTitle();
        if (StringUtils.isNotBlank(title)) {
            content += title;
        }

        // 3 抽取文章内容中的图片
        List<String> images = contentMaps.stream()
                .filter(map -> "image".equals(map.get("type")))
                .map(map -> (String) map.get("value"))
                .collect(Collectors.toList());
        // 4.抽取文章的封面图片 url1,url2,url3
        if (StringUtils.isNotBlank(wmNews.getImages())) {
            List<String> urls = Arrays.stream(wmNews.getImages().split(","))
                    //加上图片前缀
                    .map(url -> webSite + url)
                    //收集成一个list集合
                    .collect(Collectors.toList());
            images.addAll(urls);
        }
        // 对整合的图片集合进行去重运算
        images = images.stream()
                .distinct()
                .collect(Collectors.toList());
        // 将文本和图片路径塞进map集合中
        Map<String, Object> map = new HashMap<>(2);
        map.put("content", content);
        map.put("images", images);
        return map;
    }
}
